home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
Classes
/
RCString
/
RCString.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
7KB
|
332 lines
#import <RCString.h>
/*
Copyright (C) 1992. Bruce Ediger.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License.
*/
@implementation RCString
// Initialize the internal string rep, but not the
// internal string itself.
// Assumes that "self" is already allocated.
- init
{
[super init];
if (p = (struct srep *) malloc(sizeof(struct srep))) {
p->s = NULL;
p->l = 0;
p->n = 1;
}
yCaseSensitive = YES;
return self;
}
// construct an object with zero-length string internal string rep
+ new
{
RCString *oNew = [[RCString alloc] init];
if (oNew) {
oNew->p->s = malloc(1);
*oNew->p->s = '\0';
oNew->p->l = 1;
oNew->p->n = 1;
}
return oNew;
}
// Construct an object surrounding a given ASCII string.
// Should this method make a copy of the ASCIIZ argument?
// Since the object is copy-on-write, we could maybe get
// away with just keeping around the pointer. No. Then
// anything could change the string out from underneath the
// object.
+ newFromString:(char *)aString
{
RCString *oNewString;
if (aString) {
oNewString = [[RCString alloc] init];
if (oNewString) {
oNewString->p->l = strlen(aString) + 1;
if ((oNewString->p->s = malloc(oNewString->p->l))) {
bcopy(aString, oNewString->p->s, oNewString->p->l);
oNewString->p->n = 1;
} else
oNewString->p->l = 0; // malloc() failed, retain consistency
}
oNewString->yCaseSensitive = YES;
} else { // null argument string
oNewString = [RCString new];
}
return oNewString;
}
// Factory Method copy constructor analog: an object that
// references another object's internal string rep.
+ newFromObject:(RCString *) oString
{
RCString *oNewString;
if (oString && (oNewString = [RCString alloc])) {
// RCString objects will share internal string rep until a write.
oNewString->p = oString->p;
oNewString->p->n++;
oNewString->yCaseSensitive = oString->yCaseSensitive;
} else {
// passed a null object pointer: fill in a zero-length
// internal string rep
oNewString = [RCString new];
}
return oNewString;
}
// Copy constructor analog: an object that references this
// object's internal string rep.
- newFromObject
{
RCString *oNewString;
if ((oNewString = [RCString alloc]))
{
// RCString objects will share internal string rep until a write.
oNewString->p = p;
oNewString->yCaseSensitive = yCaseSensitive;
if (p) p->n++;
}
return oNewString;
}
+ newFilledWith: (int) bCharacter size: (int) iNumber
{
RCString *oNewString;
char *bpTmp;
if (bCharacter && iNumber > 0 && (bpTmp = malloc(iNumber + 1))) {
int icCount;
for (icCount = 0; icCount < iNumber + 1; ++icCount)
bpTmp[icCount] = (char )bCharacter;
bpTmp[iNumber] = '\0';
oNewString = [RCString newFromString:bpTmp];
} else {
// args specifiy null/zero-length string or malloc() failure
oNewString = [RCString new];
}
return oNewString;
}
- free
{
// should the test be "==" or "<=" ?
// <= would probably catch some mistakes.
if (p && --p->n == 0) {
// reference count's gone to zero, free internal string rep
if (p->s)
free(p->s);
free(p);
}
return [super free];
}
// private use method.
// causes the RCString object that this message is sent to,
// to copy it's internal string representation.
// typically called before modifying internal string rep
// in order to provide copy-on-write behavior.
- copyReference
{
struct srep *psNewSrep = (struct srep *)malloc(sizeof(struct srep));
if (psNewSrep) {
if (p) {
if (p->s) {
psNewSrep->s = malloc(p->l);
if (psNewSrep->s) {
bcopy(p->s, psNewSrep->s, p->l);
psNewSrep->l = p->l;
}
} else {
psNewSrep->s = NULL;
psNewSrep->l = 0;
}
// check reference count on previous internal rep
if (--p->n == 0) {
free(p->s);
free(p);
}
psNewSrep->n = 1;
p = psNewSrep;
} else {
// Object didn't have an internal string rep for some
// reason. Give it it's own NULL string
psNewSrep->s = NULL;
psNewSrep->n = 1;
psNewSrep->l = 0;
p = psNewSrep;
}
} // what if malloc() of struct srep fails?
return self;
}
- (BOOL) isNull
{
if (!p && (!p->s || p->l <= 1)) // ignore trailing ASCII NULL
return YES;
return NO;
}
// returns "strlen" of internal representation.
// that is, length without trailing NULL.
- (unsigned)length
{
if (p && p->l)
return(p->l - 1);
return 0;
}
- (char *)data
{
return p ? p->s : NULL;
}
- (int)references
{
return p ? p->n : 0;
}
- (struct srep *)internal
{
return p;
}
@end
@implementation RCString(Archiving)
// Archiving methods borrowed from John Hassey's String
// object. Try to maintain compatibility.
- storeOn: (int) aFd
{
#ifndef NeXT
[super storeOn: aFd];
#endif
if (write(aFd, &p->l, sizeof(p->l)) == -1)
{
[self error: "storeOn: write error"];
}
if (write(aFd, "\"", 1) == -1)
{
[self error: "storeOn: write error"];
}
if (write(aFd, [self data], [self length]) == -1)
{
[self error: "storeOn: write error"];
}
if (write(aFd, "\"", 1) == -1)
{
[self error: "storeOn: write error"];
}
return self;
}
- readFrom: (int) aFd
{
char c;
#ifndef NeXT
[super readFrom: aFd];
#endif
if (p == NULL) {
p = (struct srep *)malloc(sizeof(struct srep));
} else {
if (p->n == 1)
if (p->s) free(p->s);
else {
// Come up with a new internal rep struct. It
// will be completely redone anyway.
--p->n;
p = (struct srep *)malloc(sizeof(struct srep));
}
}
if (read(aFd, &p->l, sizeof(p->l)) == -1)
[self error: "readFrom: read error"];
p->s = malloc(p->l);
if (read(aFd, &c, 1) == -1)
[self error: "readFrom: read error"];
if (c != '"')
[self error: "readFrom: format error"];
if (read(aFd, p->s, p->l - 1) == -1)
[self error: "readFrom: read error"];
if (read(aFd, &c, 1) == -1)
[self error: "readFrom: read error"];
if (c != '"')
[self error: "readFrom: format error"];
// null terminate string
p->s[p->l - 1] = 0;
return self;
}
#ifdef NeXT
- write:(NXTypedStream *)aStream
{
[super write:aStream];
if (p)
{
int iFakeN = 1;
NXWriteType(aStream, "i", &p->l); // length first, so read: can
// allocate memory for string.
if (p->s)
NXWriteType(aStream, "*", &p->s);
else {
char *bpTmp = "";
NXWriteType(aStream, "*", &bpTmp);
}
NXWriteType(aStream, "i", &iFakeN);
NXWriteType(aStream, "c", &yCaseSensitive);
} else {
// Fake the whole internal rep as a zero-length string.
char *bpTmp = "";
int iTmpL = 1;
int iTmpN = 1;
BOOL yTmpCS = TRUE;
NXWriteType(aStream, "i", &iTmpL);
NXWriteType(aStream, "*", &bpTmp);
NXWriteType(aStream, "i", &iTmpN);
NXWriteType(aStream, "c", &yTmpCS);
}
return self;
}
- read:(NXTypedStream *)aStream
{
[super read:aStream];
// prepare internal string rep
if (p) {
if (p->n == 1) {
if (p->s) free(p->s);
} else {
--p->n;
p = (struct srep *)malloc(sizeof(struct srep));
}
} else {
p = (struct srep *)malloc(sizeof(struct srep));
}
NXReadType(aStream, "i", (void *)&p->l);
NXReadType(aStream, "*", (void *)&p->s);
NXReadType(aStream, "i", (void *)&p->n);
if (p->n != 1) [self error:"read: problem, ref count not 1"];
NXReadType(aStream, "c", (void *)&yCaseSensitive);
return self;
}
#endif
@end